#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <stdio.h>
#include <math.h>
#include <conio.h>
#include "gnuplot_i.hpp"
#define GNUPLOT_PATH "E:\\Gnuplot\\gnuplot\\binary\\"
using namespace std;
void gnuplot(double a, double b, int wybor, double c, double z)
{
  string nazwa[6]={"Wielomian","Funkcja trygonometryczna","Funkcja wykladnicza","Funkcja zlozona","Funkcja zlozona 2","Funkcja zlozona 3"};
  Gnuplot main_plot;
  main_plot.set_title(nazwa[wybor-1]);
  main_plot.set_xlabel( "x" );
  main_plot.set_ylabel( "y" );
  main_plot.set_style( "lines" );
  main_plot.set_grid();
  main_plot.set_xrange( a , b ) ;
  string wykres[6]={"x*(x*(x+2))+6","3*sin(x/5)","exp(x*log(3))-2","sin((x/2)*(x/2))","(exp((x*(x*(x))+1)*log(2))-1)","cos(x/2)*cos(x/2)+cos(x)-1/2"};
  main_plot.plot_equation(wykres[wybor-1],nazwa[wybor-1]);
  main_plot.set_style( "points" );
  main_plot.set_pointsize( 2.0 );
  vector<double> x( 1 );
    x[ 0 ] = c;
  vector<double> y ( 1 );
    y[ 0 ] = z;
  main_plot.plot_xy( x, y, "Miejsce zerowe");
  system("Pause");
}
double potega(double pod, double wyk)
{      double suma=1;
       if(wyk<0)
       {pod=1/pod;}
       if(wyk==0)
       {pod=1;}
       for(int i=1; i<=wyk;i++)
       {
       suma=suma*pod;     
       }
       return suma;
}
double wielomian_Horner(double x)
{
    return x*(x*(x+2))+6;
}
double wielomian_Horner_prim(double x)
{
    return x*(3*x+4);
}
double funkcja_trygonometryczna(double x)
{
    return (3*sin(x/5));
}
double funkcja_trygonometryczna_prim(double x)
{
    return ((3/5)*(cos(x/5)));
}
double funkcja_wykladnicza(double x)
{
    return (exp(x*log(3))-2);
}
double funkcja_wykladnicza_prim(double x)
{
    return  (exp(x*log(3))*x*log(3));
}
double funkcja_zlozona(double x)
{
    return sin(potega(x/2,2));
}
double funkcja_zlozona_prim(double x)
{
    return (cos(potega(x/2,2))*x/2);
}
double funkcja_zlozona_wyk_wiel(double x)
{
    return (exp((potega(x,3)+1)*log(2))-1);
}
double funkcja_zlozona_wyk_wiel_prim(double x)
{
    return (3*exp((potega(x,3)+1)*log(2))*potega(x,2)*log(2));
}
double funkcja_zlozona_wiel_tryg(double x)
{
    return (potega(cos(x/2),2)+cos(x)-1/2);
}
double funkcja_zlozona_wiel_tryg_prim(double x)
{
    return ((-3*sin(x))/2);
}
double f(double x, int wybor)
{
       double (*tabwsk[6])(double)={wielomian_Horner, 
       funkcja_trygonometryczna, funkcja_wykladnicza, funkcja_zlozona, 
       funkcja_zlozona_wyk_wiel, funkcja_zlozona_wiel_tryg};
       return tabwsk[wybor-1](x);
}
double fp(double x, int wybor)
{
       double (*tabwskprim[6])(double)={wielomian_Horner_prim, funkcja_trygonometryczna_prim, 
       funkcja_wykladnicza_prim, funkcja_zlozona_prim, 
       funkcja_zlozona_wyk_wiel_prim, funkcja_zlozona_wiel_tryg_prim};
       return tabwskprim[wybor-1](x);
}
int wybor_funkcji()
{
    int wybor;
    cout<<"Wybierz jedna z funkcji:\n";
    cout<<"1. Wielomian: x^3 + 2x^2 + 6\n";
    cout<<"2. Funkcja trygonometryczna: (3*sin(x/5))\n";
    cout<<"3. Funkcja wykladnicza: (3^x)-2\n";
    cout<<"4. Zlozenie funkcji: sin((x/2)^2)\n";
    cout<<"5. Zlozenie funkcji: 2^(x^3+1)-1\n";
    cout<<"6. Zlozenie funkcji: cos(x/2)^2+cos(x)-1/2\n";
    cin>>wybor;
    while(wybor<1 || wybor>6)
    {
        cout<<"\nWybierz 1, 2, 3, 4, 5 lub 6\n";
        cin>>wybor;
    }
    return wybor;
}
void wybor_zakresu(double &a, double &b, int wybor)
{
     if(wybor==2)
     {
         cout << "\nMiejsca zerowe wystepuja co 5pi. Aby miec pewnosc ze przedzial bedzie zawierac\ndokladnie jedno miejsce zerowe wybierz przedzial mniejszy niz 5pi\n";
     }
     if(wybor==6)
     {

     }
     cout<<"Podaj zakres\n";
     cin>> a;
     cin>> b;
     while(a>b || f(a,wybor)*f(b,wybor) >= 0)
    {
      cout << "Zly zakres! Funkcja musi miec rozne znaki na krancach przedzialu!\n";
      cin>> a;
      cin>> b;
    }
}
void wybor_kryterium(int &kryterium, double &epsilon, double &iteracja)
{
  cout<<"\nWybierz kryterium zatrzymania algorytmu:\n";
  cout<<"Spelnienie warunku nalozonego na dokladnosc - wybierz '1'\n";
  cout<<"Osiagniecie zadanej liczby iteracji - wybierz '2'\n";
  cin>>kryterium;
  while(kryterium!=1 && kryterium!=2)
  {
    cout<<"wybierz 1 albo 2\n";
    cin>>kryterium;
  }
  if(kryterium==1)
  {
    cout<<"Podaj epsilon:\n";
    cin>>epsilon;
  }
  else
  {
    cout<<"Podaj liczbe iteracji:\n";
    cin>>iteracja;
    int iter=iteracja;
    while(iteracja-iter!=0 || iteracja<1)
    {
      cout<<"Liczba iteracji musi byc liczba calkowita, wieksza od 1\n";
      cin>>iteracja;
      iter=iteracja;
    }
  }
}

void metoda_bisekcji(double a, double b, double epsilon, double iteracja, int kryterium, int wybor)
{
 int p=1;
 double c = (a+b)/2, m=a, n=b, z;
 if(kryterium==1) //Warunkiem jest nalozona dokladnosc
  {iteracja=1000;}else {epsilon=-10;}
   while(fabs(c-a)>epsilon && p!=iteracja)
   {
    if (f(c,wybor)*f(a,wybor)>0)
        {a = c;}
    else
        {b = c;}
        cout<< "x = " << c << " f(x)= "<< f(c,wybor) << endl;
        c = (a+b)/2;
        p+=1;
    }
        z=f(c,wybor);
        cout << "\nMetoda bisekcji:\n";
        cout << "x= " << c << " f(x)= " << z << endl;
        cout << "Wymagalo to " << p << " iteracji\n";
        gnuplot(m,n,wybor,c,z);
}
void metoda_stycznych(double a, double b, double epsilon, double iteracja, int kryterium, int wybor)
{
    int p=1;
    double x1=(a+b)/2, x0=b, f0=f(x0,wybor), f1, z;
    if(kryterium==1) //Warunkiem jest nalozona dokladnosc
    {iteracja=1000;}else {epsilon=-10;}
    while(fabs(x0-x1)>epsilon && p!=iteracja)
     {
         f1=fp(x0,wybor);
         x1=x0;
         x0=x0-f0/f1;
         cout<< "x = " << x0 << " f(x)= "<< f0 << endl;
         f0=f(x0, wybor);
         p+=1;
     }
        z=f(x0, wybor);
        cout << "\nMetoda stycznych:\n";
        cout << "x= " << x0 << " f(x)= "<< z << endl;
        cout << "Wymagalo to " << p << " iteracji\n";
        gnuplot(a,b,wybor,x0,z);
}
int main()
{
    Gnuplot::set_GNUPlotPath( GNUPLOT_PATH );
    double a, b;
    char koniec;
    do{
    system("cls");
    int wybor=wybor_funkcji();
    wybor_zakresu(a, b, wybor);
    int kryterium;
    double epsilon, iteracja=0;
    wybor_kryterium(kryterium, epsilon, iteracja);
    metoda_bisekcji(a,b,epsilon,iteracja,kryterium, wybor);
    cout<<"\n\n";
    metoda_stycznych(a,b,epsilon,iteracja,kryterium, wybor);
    cout<<"Wcisnij esc aby skonczyc\n";
    koniec=getch();
    }while(koniec!=27);
    return 0;
}

